package cn.com.haopt.udp;

import cn.com.haopt.common.config.UdpServerConfig;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * netty服务的服务端配置
 * @author haopt
 */
@Component
public class UdpServer implements Runnable{
    @Resource
    private UdpServerHandler udpServerHandler;
    @Autowired
    private UdpServerConfig udpServerConfig;

    @Override
    public void run() {
        // 相比于TCP而言，UDP不存在客户端和服务端的实际链接，因此不需要为连接(ChannelPipeline)设置handler
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            // 启动 NIO 服务的辅助启动类
            Bootstrap b = new Bootstrap();
            // 设置线程组连接
            b.group(group);
            // 配置 Channel
            b.channel(NioDatagramChannel.class);
            // 标识当服务器请求处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度
            b.option(ChannelOption.SO_BROADCAST, true);
            b.option(ChannelOption.SO_REUSEADDR, true);
            // 进入到下一步udpServerHandler
            b.handler(udpServerHandler);
            // 绑定端口，开始接收进来的连接
            ChannelFuture channelFuture = b.bind(udpServerConfig.getPort()).sync();
            // 最后绑定服务器等待直到绑定完成，调用sync()方法会阻塞直到服务器完成绑定,然后服务器等待通道关闭，因为使用sync()，所以关闭操作也会被阻塞。
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }
}
